package huanzhao.erp.other.aspect;

import cn.hutool.json.JSONUtil;
import huanzhao.erp.domain.annotation.UseCache;
import huanzhao.erp.domain.constant.CommonConstant;
import huanzhao.erp.domain.exception.ReclException;
import huanzhao.erp.domain.po.CacheOp;
import huanzhao.erp.domain.types.CacheType;
import huanzhao.erp.util.CacheEl;
import huanzhao.erp.util.CacheUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Objects;


@Component
@Aspect
public class CacheAspect {

    @Autowired
    private CacheUtils cacheUtils;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Pointcut("@annotation(huanzhao.erp.domain.annotation.UseCache)")
    public void cacheAspect() {

    }

    @Around("cacheAspect()")
    public Object doCacheAround(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature)point.getSignature();
        Method method = signature.getMethod();

        UseCache annotation = method.getAnnotation(UseCache.class);

        //定义el的key
        String elKey = null;
        //如果cache的key不为空，则解析参数
        if(!annotation.key().equals("")) {
            //获取方法参数
            String[] parameterNames = signature.getParameterNames();
            Object[] args = point.getArgs();
            //放入map方便参数解释
            HashMap<String, Object> map = new HashMap<>();
            for (int i = 0; i < parameterNames.length; i++) {
                map.put(parameterNames[i], args[i]);
            }
            elKey = CacheEl.parse(annotation.key(), map);
        }

        //生成最终的key
        String finalKey = elKey == null ? annotation.cacheGroup() + "::" + annotation.prefixKey()
                : annotation.cacheGroup() + "::" + annotation.prefixKey() + "::" + elKey;

        //执行缓存key的查询
        if(annotation.type() == CacheType.FULL) {
            //从缓存中获取value并返回
            Object res = cacheUtils.getCache(finalKey,annotation.template());
            if(Objects.nonNull(res)) return res;

            //缓存不存在查询db并放入缓存
            try {
                res = point.proceed();
            } catch (Throwable e) {
                throw new ReclException("查询db出错");
            }
            if(Objects.nonNull(res)) {
                cacheUtils.putCache(finalKey, res, annotation.expireTime(),annotation.template());
                return res;
            }
        }

        //执行缓存Key的更新操作
        if(annotation.type() == CacheType.PUT) {
            //更新数据库
            Object res = null;
            try {
                res = point.proceed();
            } catch (Throwable e) {
                throw new ReclException("db更新出错");
            }
            //更新缓存
            cacheUtils.putCache(finalKey, res, annotation.expireTime(),annotation.template());
            return res;
        }

        //执行缓存Key的删除操作
        if(annotation.type() == CacheType.DELETE) {
            //更新数据库
            Object res = null;
            try {
                res = point.proceed();
            } catch (Throwable e) {
                throw new ReclException("db删除出错");
            }
            //更新缓存
            cacheUtils.delCache(finalKey,annotation.template());
            return res;
        }

        throw new ReclException("操作缓存失败");
    }
}